#pragma once 
#include "Thread.hpp"
#include "Cond.hpp"
#include "Mutex.hpp"
#include "Log.hpp"
#include <vector>
#include <memory>
#include <functional>
#include <queue>
#include <unistd.h>
namespace MyThreadPoolMudule
{
    using namespace MyLogModule;
    using namespace MyCondModule;
    using namespace MyMutexModule;
    using namespace MyThreadmodule;
    using thread_t = std::shared_ptr<Thread>;
    const int gdefaultnum = 10;

    template<class T>
    class ThreadPool
    {
    private:
        //线程启动执行的函数
        void HandlerRequest(const string& name){
            LOG(LogLevel::INFO) << name << "进入HandlerRequest处理逻辑";
            while(1){
                T t;
                {
                    LockGuard lock(_mutex);
                    while(_isrunning && _bq.empty()){
                        //如果线程池运行着并且任务队列为空, 就去条件变量等待
                        LOG(LogLevel::DEBUG) << "等待线程数量: " << _waitnum;
                        _waitnum++;
                        LOG(LogLevel::DEBUG) << name << "陷入等待";
                        _cond.Wait(_mutex);
                        LOG(LogLevel::DEBUG) << name << "被唤醒";
                        _waitnum--;
                    }
                    if (_bq.empty() && !_isrunning) {
                        //如果任务队列没有任务了 并且 线程池没有运行就直接退出即可
                        return;
                    }
                    t = std::move(_bq.front());
                    _bq.pop();
                }
                t();
                LOG(LogLevel::INFO) << name  << "执行完毕任务";
            }
        }
    private:
        ThreadPool(int threadnum = gdefaultnum)
            :_threadnum(threadnum),_waitnum(0),_isrunning(false)
        {
            for (int i = 0; i < _threadnum; i++){
                //参数让线程自己传递去
                _threads.emplace_back(std::make_shared<Thread>(std::bind(&ThreadPool::HandlerRequest,this,std::placeholders::_1)));
            }
            //开辟了就只接启动, 我调用的时候直接enque
            Start();
        }
        ThreadPool(const ThreadPool<T>& p) = delete;
        ThreadPool<T>& operator=(const ThreadPool<T>& p) = delete;
    public:
        static Mutex lock;
        static ThreadPool<T>* _instance;

        static ThreadPool<T>* GetInstance(){
            LOG(LogLevel::DEBUG) << "获取单例线程池";
            if (_instance == nullptr){
                LockGuard lock(lock);
                if (_instance == nullptr){
                    _instance = new ThreadPool<T>(gdefaultnum);
                    return _instance;
                }
            }
            return _instance;
        }

        void Start(){
            if (_isrunning) {
                LOG(LogLevel::WARNING) << "线程池已经启动了, 不需要重复启动";
                return;
            }
            //先把标志位置为1, 再启动线程, 不然有些线程可能直接回退出
            _isrunning = true;
            for (auto& ptr:_threads){
                ptr->Start();
            }
        }

        template<typename U>
        void Enque(U&& data){
            //其实这里好像不加锁都可以, 主要我们现在是只有一个用户
            LockGuard lock(_mutex);
            _bq.emplace(std::forward<U>(data));
            if (_waitnum > 0){
                _cond.NotifyAll(); //直接通知所有等待线程来争先恐后的抢夺任务
                //这里不要动_waitnum, 不然我们阻塞住的就会把它减为负数, 那就不会再通知了
                // _waitnum = 0;
            }   
        }   
        void Stop(){
            if (!_isrunning){
                LOG(LogLevel::ERROR) << "还没有启动线程池, 不能停止";
                return;
            }
            _isrunning = false;
            _cond.NotifyAll(); //都要结束了, 就唤醒所有的线程赶紧执行任务
            for (auto& ptr : _threads){
                ptr->Join();
                LOG(LogLevel::DEBUG) << "等待线程[" << ptr->Name() << "]成功";
            }
        }

    private:
        vector<thread_t> _threads; //线程数组
        queue<T> _bq;
        bool _isrunning;
        int _threadnum;
        Cond _cond;
        Mutex _mutex;
        int _waitnum; //在条件变量中等待用户发布任务的线程
    };

    template<class T>
    Mutex ThreadPool<T>::lock;
    
    template<class T>
    ThreadPool<T>* ThreadPool<T>::_instance = nullptr;

}